#!/usr/bin/env python
import sys

import pygame

from lib.singleton import Singleton, Handle
#More imports at the bottom and in Main.__init__

class Key:
    def __init__(self):
        self.pressed = set()
        self.pressedPrev = set()
    
    def check(self, key):
        """Checks if a key is pressed, returns bool"""
        return True if key in self.pressed else False
    
    def checkPrev(self, key):
        """Checks if a key was pressed last frame, returns bool"""
        return True if key in self.pressedPrev else False
    
    def checkPressed(self, key):
        """Checks if a key has just been pressed, returns bool"""
        return True if self.check(key) and not self.checkPrev(key) else False
    
    def checkReleased(self, key):
        """Checks if a key has just been released, returns bool"""
        return True if not self.check(key) and self.checkPrev(key) else False
    
class Mouse:
    def __init__(self):
        self.x = 0
        self.y = 0
        self.xPrev = 0
        self.yPrev = 0
        
        self.pressed = (0,0,0)
        self.pressedPrev = (0,0,0)
        self.pressedTime = 0
        
        self.wheel = 0
    
    def checkPressed(self, button=None):
        if button:
            return self.pressed[button]
        else:
            return self.pressed[0] or self.pressed[1] or self.pressed[2]
    
    def checkClicked(self, button=None):
        if button != None:
            return self.pressed[button] and not self.pressedPrev[button]
        else:
            return (self.pressed[0] and not self.pressedPrev[0]) or \
                   (self.pressed[1] and not self.pressedPrev[1]) or \
                   (self.pressed[2] and not self.pressedPrev[2])
    
    def checkReleased(self, button=None):
        if button != None:
            return not self.pressed[button] and self.pressedPrev[button]
        else:
            return (not self.pressed[0] and self.pressedPrev[0]) or \
                   (not self.pressed[1] and self.pressedPrev[1]) or \
                   (not self.pressed[2] and self.pressedPrev[2])

class Main(Singleton):
    def __init__(self):
        Singleton.__init__(self)
        
        #Pygame extra inits
        #pygame.mixer.init()
        pygame.font.init()
        
        #Constants
        self.displaySize = self.w, self.h = 800, 400
        self.fpsCap = 60
        
        #Pygame modules
        self.display = pygame.display.set_mode(self.displaySize)
        self.key = Key()
        self.mouse = Mouse()
        self.clock = pygame.time.Clock()
        
        #Objects
        from lib.config import Config
        from lib.dynamics import World, Fluid
        from lib.sodalike import Wave
        from lib.gui.behavior import BehaviorHandler
        from lib.gui.interface import Interface
        
        self.config = Config("config.conf")
        self.world = World()
        self.wave = Wave()
        self.fluid = Fluid(length=5, stiffness=0.05)
        self.behaviorHandler = BehaviorHandler()
        self.interface = Interface()
        
        #Groups
        self.updateList = [self.world,
                           self.fluid,
                           self.wave,
                           self.behaviorHandler,
                           self.interface]
        
        self.alwaysUpdateList = [self.behaviorHandler,
                                 self.interface]
        
        self.drawList = [self.interface]
        
        #Flags and others
        self.loopFlag = True
        self.pause = False
        self.debug = False
        self.counter = 0
    
    def loop(self):
        while True:
            #Event handling
            events = pygame.event.get()
            
            self.key.pressedPrev = set(self.key.pressed)
            
            self.mouse.wheel = 0
            
            for event in events:
                if event.type == pygame.QUIT:
                    import sys
                    sys.exit()
                
                elif event.type == pygame.KEYDOWN:
                    self.key.pressed.add(event.key)
                elif event.type == pygame.KEYUP:
                    try:
                        self.key.pressed.remove(event.key)
                    except KeyError:
                        #Happens when you mess with the window(move it etc.)
                        pass
                
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 4:
                        self.mouse.wheel = -1
                    elif event.button == 5:
                        self.mouse.wheel = 1
            
            self.mouse.xPrev = self.mouse.x
            self.mouse.yPrev = self.mouse.y
            self.mouse.pressedPrev = self.mouse.pressed
            
            self.mouse.x, self.mouse.y = pygame.mouse.get_pos()
            self.mouse.pressed = mp = pygame.mouse.get_pressed()
            
            if mp[0] or mp[2] or mp[1]:
                self.mouse.pressedTime += 1
            else:
                self.mouse.pressedTime = 0
            #End of input handling
            
            #Stuff
            if self.key.checkPressed(pygame.K_SPACE):
                self.pause = not self.pause
            
            #Logic
            if self.pause:
                for instance in self.alwaysUpdateList:
                    instance.update()
            else:
                for instance in self.updateList:
                    instance.update()
            
            #Graphics
            for instance in self.drawList:
                instance.on_draw(self.display)
            
            #End frame
            pygame.display.flip()
            dt = self.clock.tick(self.fpsCap) / 1000.0
            if not self.pause:
                self.counter += dt

main = Handle(Main)

if __name__ == '__main__':
    try:
        import psyco
        psyco.log()
        psyco.full(memory=100)
        psyco.profile(0.05, memory=100)
        psyco.profile(0.2)
    except ImportError:
        if __debug__:
            print "Get psyco!"
    
    if __debug__:
        from lib.debug import Debug
        debug = Debug()
        main.alwaysUpdateList.append(debug)
        main.updateList.append(debug)
        
        import cProfile
        cProfile.run('main.loop()')
    else:
        main.loop()
